﻿#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "defines.h"
#include "seg.h"
#include "mem_pool.h"
#include "sync.h"

static void _seg_alloc_page(SEG_TABLE** seg, int page_id);

SEG_TABLE* seg_create(int seg_table_size, int page_size, int iterm_size)
{
	SEG_TABLE* ret;
	
	if (seg_table_size<=0 || page_size<=0 || iterm_size<=0 || page_size<iterm_size )
	{
		printf ("error arguement. seg_table_size:%d\tpage_size:%d\titerm_size:%d\n", seg_table_size, page_size, iterm_size);
		return NULL;
	}

	if (seg_table_size==SEG_TABLE_INIT_NR) 
	{
        	ret = mp_alloc(sizeof(SEG_TABLE));
	}
	else 
	{
        	ret = mp_alloc(sizeof(SEG_TABLE)+(seg_table_size-SEG_TABLE_INIT_NR)*4);
	}

	ret->table_size=seg_table_size;
	ret->page_size=page_size;
	ret->iterm_size=iterm_size;
	ret->iterm_nr_in_page=page_size/iterm_size;

	ret->iterm_horizon=0;
	ret->cur_page_id=0;
	_seg_alloc_page(&ret, 0);

	return ret;
}

STATE seg_free(SEG_TABLE* seg)
{
	int i;
	
	if (seg==NULL)
	{
		printf ("seg pointer is NULL.\n");
		return SEG_FREE_FAIL;
	}
	
	for (i=0; i<seg->cur_page_id; i++) 
	{
        	mp_free(seg->seg[i]);
	}
	
	mp_free(seg);
	return SEG_FREE_SUCCESS;
}


/* whne load, page_size& seg_page_id --> unchange */
void seg_load(SEG_TABLE** seg, PTR_DISK _start, int seg_page_id)
{
	int i;
	STATE state;
	for (i=1; i<=seg_page_id; i++) 
	{
        	_seg_alloc_page(seg,i); /* XXX: whthout table_size leak many times problems */
	}
	printf ("seg_load:\tpage_size: %d\t seg_page_id:%d\n", (*seg)->page_size, seg_page_id);
	state=sync_read_2(_start, (*seg)->seg, (*seg)->page_size, seg_page_id);
	if (state==IO_READ_FAIL) printf ("read failed.\n");
	(*seg)->cur_page_id=seg_page_id;
}


void seg_save(SEG_TABLE* seg, PTR_DISK _start)
{
	sync_write_2(_start, seg->seg, seg->page_size, seg->cur_page_id);
	/* _start */
}

/* do not deal with seg->cur_page_id */
static void _seg_alloc_page(SEG_TABLE** seg, int page_id)
{
	SEG_TABLE* pre;
	int i;
	pre=*seg;
	if (page_id>=(*seg)->table_size) 
	{
		(*seg)=seg_create(((*seg)->table_size)*2, (*seg)->page_size, (*seg)->iterm_size );
		(*seg)->iterm_nr_in_page=pre->iterm_nr_in_page;
		(*seg)->iterm_horizon=pre->iterm_horizon;
		(*seg)->cur_page_id=pre->cur_page_id;

		for (i=0; i<pre->table_size; i++) (*seg)->seg[i]=pre->seg[i];
		mp_free(pre);
	}

	(*seg)->seg[page_id]=mp_alloc((*seg)->page_size);		
}


void  seg_put_iterm(SEG_TABLE** seg, char* iterm)
{
	char *p;
	SEG_TABLE* seg_ptr=*seg;

	p=seg_ptr->seg[seg_ptr->cur_page_id];
	p+=(seg_ptr->iterm_horizon)*(seg_ptr->iterm_size);
	memcpy(p, iterm, seg_ptr->iterm_size);


	seg_ptr->iterm_horizon++;
	if (seg_ptr->iterm_horizon==seg_ptr->iterm_nr_in_page)
	{
		(seg_ptr->cur_page_id)++;
		_seg_alloc_page(seg, seg_ptr->cur_page_id);
		seg_ptr=*seg; /*XXX:BUG FIXed***/
		seg_ptr->iterm_horizon=0;
	}
}

STATE  seg_get_iterm(SEG_TABLE* seg, char* iterm)
{
	char *p=NULL;
	if (seg->cur_page_id<=0 && seg->iterm_horizon<=0) return SEG_GET_FAIL;
	if (seg->iterm_nr_in_page!=((seg->page_size)/(seg->iterm_size))) return SEG_GET_FAIL;

	if (seg->iterm_horizon==0)
	{
		mp_free(seg->seg[seg->cur_page_id]);
		seg->cur_page_id--;
		seg->iterm_horizon=seg->iterm_nr_in_page;
	}
	seg->iterm_horizon--;
	p=seg->seg[seg->cur_page_id];
	p+=(seg->iterm_horizon)*(seg->iterm_size);
	
	memcpy((void*)iterm, (const void*)p, (size_t)(seg->iterm_size));
	return SEG_GET_SUCCESS;
}
	
void seg_show(SEG_TABLE* seg)
{
	int i,j;
	char *p=NULL;
	printf ("SEG:\n");
	printf ("table_size:%d\n",seg->table_size);
	printf ("page_size:%d\n", seg->page_size);
	printf ("iterm_size:%d\n", seg->iterm_size);
	printf ("iterm_nr_in_page:%d\n", seg->iterm_nr_in_page);
	printf ("iterm_horizon:%d\n", seg->iterm_horizon);
	printf ("cur_page_id:%d\n", seg->cur_page_id);


	for (i=0; i<seg->cur_page_id; i++)
	{
		for (j=0; j<seg->iterm_nr_in_page; j++)
		{
			p=seg->seg[i];
			p+=j*seg->iterm_size;
			printf ("%d:%d\n",j, *((int*)p));
		}
	}
	for (j=0; j<seg->iterm_horizon; j++)
	{
		p=seg->seg[i];
		p+=j*seg->iterm_size;
		printf ("%d:%d\n",j, *((int*)p));
	}
}

void* seg_get_ptr(SEG_TABLE* seg)
{
	char *p=NULL;
	if (seg->cur_page_id==1 && seg->iterm_horizon==0) return NULL;
	if (seg->iterm_horizon==0)
	{
		mp_free(seg->seg[seg->cur_page_id]);
		seg->cur_page_id--;
		seg->iterm_horizon=seg->iterm_nr_in_page;
	}	
	seg->iterm_horizon--;
	p=seg->seg[seg->cur_page_id];
	p+=(seg->iterm_horizon)*(seg->iterm_size);
	return p;
}


//Addressing Method:
//1.FULL(free node list)
//2.end_sign && bool compare func();

/*
in Method 1, free node list:
	address will never be continous, and it'll convinient to SYNC_PACKET model. for the reason that free-node-list will finally sync to hardisk, and in hardisk, it is packages.

in Method 2, end_sign, expecially for IDX_NODE
	since it finally model in hardisk is "2).Dynamic with MAX", no need for packages, but if using packaging, it will be easy for address in idx_node_ptr( for the reason that: with the help of FREE_NODE pattern, valid_ptr is increasing all the time, it is easy to create a relation between 'real use MEMORY' and 'valid_logic_ptr'). and seemed cause no hard to sync() or init();
*/

